﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
namespace EzFrameWork
{
    public class EzTCPSever
    {
        private int MaxListen = 0;

        private int Port;
        Thread listenthread;//监听客户端链接线程
        Thread SendHertThread;//用于发送心跳包的线程
        public Dictionary<string, EzTCPUser> EzTcpUserDic;
        Socket ClientSocket;//服务器Socket
        Socket socketWatch;
        public Action<MessageType, byte[]> Response;

        private int index = 0;

        public int HertCD = 1000;//发送心跳包的时间间隔 毫秒/次
        public EzTCPSever()
        {
            EzTcpUserDic = new Dictionary<string, EzTCPUser>();
        }
        
        public EzTCPSever(int Port, int MaxListen = 0)
        {
            EzTcpUserDic = new Dictionary<string, EzTCPUser>();
            this.Port = Port;
            this.MaxListen = MaxListen;
        }

        /// <summary>
        /// 发送心跳包
        /// </summary>
        private void SendHertbyThread()
        {
            Hert h = new Hert();
            h.ID = "Sever";
            h.Time = DateTime.Now;
            byte[] hertData = EzDataRWS.ObjectToBytes(h);
            SendAllSockets(MessageType.HERTPACK, hertData);
        }

        /// <summary>
        /// 分配一个未使用的ID
        /// </summary>
        private string GetNewID()
        {
            int ID = index++;
            return ID.ToString();
        }

        /// <summary>
        /// 显示所有IP
        /// </summary>
        public void ShowSeverIP()
        {
            for (int i = 0; i < GetLocalIp().Count; i++)
            {
                GUI.Label(new Rect(0, 0, 200, 200), GetLocalIp()[i]);
            }
        }

        //获取自身IP
        public List<string> GetLocalIp()
        {
            ///获取本地的IP地址
            string AddressIP = string.Empty;
            List<string> vs = new List<string>();
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                    vs.Add(AddressIP);
                }
            }
            return vs;
        }

        /// <summary>
        /// 开启服务器
        /// </summary>
        public void StartServer()
        {
            try
            {
                //点击开始监听时 在服务端创建一个负责监听IP和端口号的Socket
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //创建对象端口
                IPEndPoint point = new IPEndPoint(IPAddress.Any, Port);
                socketWatch.Bind(point);//绑定端口号
                socketWatch.Listen(MaxListen);//设置监听，最大同时连接
                ClientSocket = socketWatch;
                //创建监听线程
                listenthread = new Thread(Listen);
                listenthread.IsBackground = true;
                listenthread.Start(socketWatch);
                //SendHertThread = new Thread(SendHertToAllClient);
                //SendHertThread.Start();

                Debug.Log("成功开启服务器");
            }
            catch (Exception ex)
            {
                Debug.LogError(ex);
            }
        }

        private void SendHertToAllClient()
        {
            Debug.Log("开始发送心跳包");
            while (socketWatch!=null&&socketWatch.IsBound)
            {
                Thread.Sleep(1000);//每隔一秒发送一次心跳包
                SendHertbyThread();
                Debug.Log("发送了心跳包");
            }
            Debug.Log("停止发送心跳包");
        }
        /// <summary>
        /// 关闭服务器
        /// </summary>
        public void CloseServer()
        {
            if (socketWatch != null)
            {
                socketWatch.Close();
            }

            if (listenthread != null)
            {
                listenthread.Abort();
            }

            if (ClientSocket != null)
            {
                ClientSocket.Close();
            }

            foreach (var item in EzTcpUserDic)
            {
                item.Value.CloseLink();
            }
            //SendHertThread.Abort();
            Debug.Log("成功关闭服务器");
        }

        /// <summary>
        /// 等待客户端的连接 并且创建与之通信的Socket
        /// </summary>
        void Listen(object o)
        {
            Socket socketWatch = o as Socket;
            while (true)
            {
                try
                {
                    ClientSocket = socketWatch.Accept();//等待接收客户端连接
                    string ID = GetNewID();
                    Debug.Log("ID:" + ID + ":" + "连接成功!");
                    //开启一个新线程，执行接收消息方法
                    Thread r_thread = new Thread(Received);
                    r_thread.IsBackground = true;
                    r_thread.Start(ClientSocket);
                    EzTCPUser ezTCPUser = new EzTCPUser(ClientSocket, r_thread);
                    EzTcpUserDic.Add(ID, ezTCPUser);
                    Debug.Log("这个客户端ID为：" + ID);
                    SendData(ID, MessageType.SENDID, Encoding.UTF8.GetBytes(ID));
                }
                catch (Exception e)
                {
                    socketWatch.Close();//关闭客户端
                    Debug.Log("关闭服务器监听");
                    break;//跳出循环
                }
            }
        }

        /// <summary>
        /// 服务器端不停的接收客户端发来的消息
        /// </summary>
        /// <param name="o"></param>
        void Received(object o)
        {
            Socket socketSend = o as Socket;
            while (true)
            {
                try
                {
                    NetworkStream netStream = new NetworkStream(socketSend);
                    byte[] datasize = new byte[4];
                    netStream.Read(datasize, 0, 4);
                    int size = System.BitConverter.ToInt32(datasize, 0);
                    byte[] message = new byte[size];
                    int dataleft = size;
                    int start = 0;
                    while (dataleft > 0)
                    {
                        int recv = netStream.Read(message, start, dataleft);
                        start += recv;
                        dataleft -= recv;
                    }
                    if (message.Length > 0)
                    {
                        MessageAgreement.ReadSimpleDataPack(message, (T, D) =>
                        {
                            Response(T, D);
                        });
                    }
                }
                catch (Exception e)
                {
                    Debug.Log("取消监听客户端" + e);
                    break;
                }
            }
        }

        /// <summary>
        /// 服务器向特定客户端发送消息
        /// </summary>
        /// <param name="str"></param>
        public void SendData(string ID, MessageType messageType, byte[] data)
        {
            Debug.Log("发送ID：" + ID);
            if (EzTcpUserDic.ContainsKey(ID))
            {
                try
                {
                    byte[] TempData = MessageAgreement.WriteSimpleDataPack(data, messageType);
                    EzTcpUserDic[ID].socket.Send(TempData);
                    Debug.Log("发送的内容为：" + Encoding.UTF8.GetString(data));
                }
                catch (Exception e)
                {
                    Debug.Log(e);
                    Debug.Log("发送给ID为："+ ID + "的客户端数据时发生意如上错误所以关闭与这个客户端的链接");
                    EzTcpUserDic[ID].CloseLink();
                    EzTcpUserDic.Remove(ID);
                    Debug.Log("成功关闭：" + ID);
                }
            }
        }

        List<string> ksys = new List<string>();

        /// <summary>
        /// 向所有的客户端发送消息
        /// </summary>
        /// <param name="data"></param>
        public void SendAllSockets(MessageType messageType, byte[] data)
        {
            //先检查有没有无效的链接
            if (ksys.Count>0)
            {
                foreach (var item in ksys)
                {
                    EzTcpUserDic.Remove(item);
                }
            }

            foreach (var item in EzTcpUserDic)
            {
                try
                {
                    byte[] tempdata = MessageAgreement.WriteSimpleDataPack(data, messageType);
                    item.Value.socket.Send(tempdata);
                }
                catch (Exception ex)
                {
                    ksys.Add(item.Key);//将无法使用的链接添加到表中等待下一轮关闭链接
                    Debug.Log("向客户端：" +item.Key + "发送数据失败主动断开链接");
                }
            }
        }
    }
}